package com.xiang.community.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiang.community.annotation.LoginRequired;
import com.xiang.community.bo.MessageBO;
import com.xiang.community.constant.KafkaConstant;
import com.xiang.community.dto.ResultDTO;
import com.xiang.community.entity.User;
import com.xiang.community.enums.ResponseCodeEnum;
import com.xiang.community.enums.UserFocusStatusEnum;
import com.xiang.community.exceptions.BusinessException;
import com.xiang.community.message.MessageProducer;
import com.xiang.community.service.CommonService;
import com.xiang.community.service.UserService;
import com.xiang.community.utils.CookieUtil;
import com.xiang.community.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static com.xiang.community.constant.LoginConstant.MAP_KEY_TOKEN;
import static com.xiang.community.constant.RedisUtilConstant.*;

/**
 * @author qixiangLi
 * @Date 2021/11/7
 */
@RestController
@Slf4j
@RequestMapping("/admin/profile")
public class AdminController {
    @Resource
    private UserService userService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private ObjectMapper mapper;
    @Resource
    private HttpServletRequest request;
    @Resource
    private CommonService commonService;
    @Resource
    private MessageProducer messageProducer;

    /**
     * 获取用户信息
     *
     * @param userId
     * @return
     */
    @GetMapping("/{userId}")
    public ResultDTO getProfile(@PathVariable Integer userId) {
        User user = commonService.getUserByUserId(userId);
        if (user == null) {
            return ResultDTO.builder().code(ResponseCodeEnum.CLIENT_ERROR.getCode()).message("用户不存在").build();
        }

        Map<String, Object> map = new HashMap<>(1);
        map.put("info", user);
        return ResultDTO.builder().code(ResponseCodeEnum.SUCCESS.getCode()).data(map).build();
    }

    /**
     * 关注与取关
     *
     * @param userId
     * @return
     */
    @GetMapping("/focus/{userId}")
    @LoginRequired
    public ResultDTO focus(@PathVariable Integer userId) throws JsonProcessingException {
        User userTwo = commonService.getUserByUserId(userId);
        if (userTwo == null) {
            return ResultDTO.builder().code(ResponseCodeEnum.CLIENT_ERROR.getCode()).message("用户不存在").build();
        }

        String userOneId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        User userOne = commonService.getUserByUserId(userOneId);
        boolean focused = redisUtil.isMemberOfSet(PREFIX_USER_FOLLOWER, userOne.getId(), userTwo.getId());
        if (focused) {
            this.removeFocus(userId);
        } else {
            this.saveFocus(userOne, userTwo);
        }
        return ResultDTO.builder().code(ResponseCodeEnum.SUCCESS.getCode()).build();
    }

    /**
     * 关注
     *
     * @param userOne
     * @param userTwo
     * @throws JsonProcessingException
     */
    private void saveFocus(User userOne, User userTwo) throws JsonProcessingException {
        redisUtil.saveIntoSet(PREFIX_USER_FOLLOWEE, userTwo.getId(), userOne.getId());
        redisUtil.saveIntoSet(PREFIX_USER_FOLLOWER, userOne.getId(), userTwo.getId());
        userTwo.setFolloweeCount(userTwo.getFolloweeCount() + 1);
        userOne.setFollowerCount(userOne.getFollowerCount() + 1);
        redisUtil.saveIntoString(PREFIX_USER, userTwo.getId(), mapper.writeValueAsString(userTwo));
        redisUtil.saveIntoString(PREFIX_USER, userOne.getId(), mapper.writeValueAsString(userOne));

        Map<String, Object> map = new HashMap<>(2);
        map.put("userOneId", userOne.getId());
        map.put("userTwoId", userTwo.getId());
        MessageBO messageBO = MessageBO.builder().fromUserName(userOne.getUsername())
                .toUserId(userTwo.getId()).data(map).build();
        messageProducer.sendMessage(KafkaConstant.TOPIC_FOLLOW, mapper.writeValueAsString(messageBO));
    }

    /**
     * 取关
     *
     * @param userId
     * @return
     * @throws JsonProcessingException
     */
    private void removeFocus(@PathVariable Integer userId) throws JsonProcessingException {
        User userTwo = commonService.getUserByUserId(userId);
        if (userTwo == null) {
            throw new BusinessException(ResponseCodeEnum.CLIENT_ERROR.getCode(), "用户不存在");
        }

        // 当前登录用户
        String userOneId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        User userOne = commonService.getUserByUserId(userOneId);

        // 被取关者的关注者人数-1
        userTwo.setFolloweeCount(userTwo.getFolloweeCount() - 1);
        redisUtil.saveIntoString(PREFIX_USER, userTwo.getId(), mapper.writeValueAsString(userTwo));
        redisUtil.removeFromSet(PREFIX_USER_FOLLOWEE, userTwo.getId(), userOne.getId());

        // 取关者关注的人数-1
        userOne.setFollowerCount(userOne.getFollowerCount() - 1);
        redisUtil.saveIntoString(PREFIX_USER, userOne.getId(), mapper.writeValueAsString(userOne));
        redisUtil.removeFromSet(PREFIX_USER_FOLLOWER, userOne.getId(), userTwo.getId());

        Map<String, Object> map = new HashMap<>(2);
        map.put("userOneId", userOne.getId());
        map.put("userTwoId", userTwo.getId());
        MessageBO messageBO = MessageBO.builder().fromUserName(userOne.getUsername())
                .toUserId(userTwo.getId()).data(map).build();
        messageProducer.sendMessage(KafkaConstant.TOPIC_UNFOLLOW, mapper.writeValueAsString(messageBO));
    }

    /**
     * 获取当前用户与某个用户的关注状态
     *
     * @param userId
     * @return
     */
    @GetMapping("/focusStatus/{userId}")
    @LoginRequired
    public ResultDTO getFocusStatus(@PathVariable Integer userId) {
        String currentUserId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        Map<String, Object> map = new HashMap<>(1);
        map.put("focusStatus", this.getFocusStatus(userId, currentUserId));
        return ResultDTO.builder().code(ResponseCodeEnum.SUCCESS.getCode()).data(map).build();
    }

    /**
     * 关注列表
     *
     * @param userId
     * @return
     */
    @GetMapping("/followerSet/{userId}")
    @LoginRequired
    public ResultDTO getFollowerList(@PathVariable Integer userId) {
        return this.getFollowList(userId, PREFIX_USER_FOLLOWER, "followerSet");
    }

    /**
     * 关注者列表
     *
     * @param userId
     * @return
     */
    @GetMapping("/followeeSet/{userId}")
    @LoginRequired
    public ResultDTO getFolloweeList(@PathVariable Integer userId) {
        return this.getFollowList(userId, PREFIX_USER_FOLLOWEE, "followeeSet");
    }

    /**
     * 关注列表信息or关注者列表信息
     *
     * @param userId
     * @param prefix
     * @param mapKey
     * @return
     */
    private ResultDTO getFollowList(@PathVariable Integer userId, String prefix, String mapKey) {
        String currentUserId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        User user = commonService.getUserByUserId(currentUserId);
        if (user.getId() != userId) {
            return ResultDTO.builder().code(ResponseCodeEnum.CLIENT_ERROR.getCode()).message("无法获取其他用户的关注列表").build();
        }

        Set<String> followerIdSet = redisUtil.getValuesFromSet(prefix, userId);
        Set<User> followerSet = new HashSet<>(followerIdSet.size());
        for (String id : followerIdSet) {
            followerSet.add(userService.findUserById(Integer.valueOf(id)));
        }
        Map<String, Object> map = new HashMap<>(1);
        map.put(mapKey, followerSet);
        return ResultDTO.builder().code(ResponseCodeEnum.SUCCESS.getCode()).data(map).build();
    }

    /**
     * 关注状态：未关注、已关注、互相关注
     *
     * @param userTwoId
     * @param userOneId
     * @return
     */
    private int getFocusStatus(Object userTwoId, Object userOneId) {
        int focusStatus = 0;
        if (redisUtil.isMemberOfSet(PREFIX_USER_FOLLOWER, userOneId, userTwoId)) {
            focusStatus = UserFocusStatusEnum.TWO.getStatus();
            if (redisUtil.isMemberOfSet(PREFIX_USER_FOLLOWER, userTwoId, userOneId)) {
                focusStatus = UserFocusStatusEnum.THREE.getStatus();
            }
        }
        return focusStatus;
    }
}
